package com.cloud.point.concurrent.threadPool;

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;

/**
 * TestExecutors
 *
 * @author H
 * @version 1.0
 * @date 2024-05-23 17:42
 */
@Slf4j
public class TestExecutors {

    public static void main(String[] args) throws Exception {

        testMethods();
        exceptionHandle();
        schedPrac();
        testQueue();

    }

    private static void testQueue() {
        final int SIZE = 50_0000;
        /**
         * LinkedBlockingQueue，Integer.MAX_VALUE
         */
        ExecutorService pool = Executors.newFixedThreadPool(5);
        /**
         * SynchronousQueue;  maximumPoolSize:Integer.MAX_VALUE
         * 比较适合处理执行时间比较小的任务
         */
        ExecutorService pool2 = Executors.newCachedThreadPool();
        /**
         * LinkedBlockingQueue，Integer.MAX_VALUE
         */
        ExecutorService pool3 = Executors.newSingleThreadExecutor();
        /**
         * DelayedWorkQueue ； maximumPoolSize:Integer.MAX_VALUE
         */
        ExecutorService pool4 = Executors.newScheduledThreadPool(5);

        SynchronousQueue<Runnable> queue = new SynchronousQueue<>();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(0, 1_0000, 30, TimeUnit.SECONDS, queue);

        for (int i = 0; i < SIZE; i++) {
            final int swap = i;
            executor.submit(() -> {
                log.info("执行任务:{}|<|>|thread-id:{}", swap, Thread.currentThread().getId());
            });
        }
        executor.shutdown();

    }

    /**
     * 定时任务运用
     */
    private static void schedPrac() {
        LocalDateTime now = LocalDateTime.now();
        // 获取目标执行时间
        LocalDateTime targetDate = now.with(DayOfWeek.FRIDAY).withHour(0).withMinute(29).withSecond(0).withNano(0);
        // 如果当前时间已经超过 本周四 18:00:00.000， 那么找下周四 18:00:00.000
        if (!now.isBefore(targetDate)) {
            targetDate = targetDate.plusWeeks(1);
        }
        // 计算时间差，即延时执行时间
        long initialDelay = Duration.between(now, targetDate).toMillis();
        // 计算间隔时间，即 1 周的毫秒值
        long oneWeek = 7 * 24 * 3600 * 1000;
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
        log.info("开始时间:{}", LocalDateTime.now());
        executor.scheduleAtFixedRate(() -> {
            log.info("定时任务执行时间：{}", LocalDateTime.now());
        }, initialDelay, oneWeek, TimeUnit.MILLISECONDS);

    }

    /**
     * 两种延时执行方法
     */
    private static void testMethods() {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);

        pool.scheduleAtFixedRate(() -> {
            try {
                log.info("rate 1开始");
                int i = 1 / 0;
                Thread.sleep(2000);
            } catch (Exception e) {
                log.warn("", e);
                //throw new RuntimeException(e);
            }
            log.info("rate 结束");
        }, 1, 1, TimeUnit.SECONDS);

        pool.scheduleWithFixedDelay(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("rate 2");
        }, 1, 1, TimeUnit.SECONDS);
    }

    /**
     * 线程池异常处理
     *
     * @throws InterruptedException
     */
    private static void exceptionHandle() throws InterruptedException {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
        /**
         * 线程池中的线程执行任务，如果任务出现异常，不会影响执行后面的任务
         * 异常需要手动处理，线程池不会抛出异常
         *
         * 1.异常通过 try 块包裹捕获
         * 2.异常通过线程池的返回接口 Future 可以获取返回结果
         */
        pool.schedule(() -> {
            try {
                log.info("p1");
                int i = 1 / 0;
                return true;
            } catch (Exception e) {
                log.warn("", e);
            }
            return false;
        }, 1, TimeUnit.SECONDS);

        pool.schedule(() -> {
            log.info("p2");
        }, 1, TimeUnit.SECONDS);

        pool.shutdown();
        // awaitTermination作用是等待线程池中任务执行完毕
        pool.awaitTermination(1, TimeUnit.SECONDS);
        log.info("main other");

    }

}
